home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / octa209s.zip / octave-2.09 / src / pt-plot.cc < prev    next >
C/C++ Source or Header  |  1997-03-07  |  24KB  |  1,190 lines

  1. /*
  2.  
  3. Copyright (C) 1996 John W. Eaton
  4.  
  5. This file is part of Octave.
  6.  
  7. Octave is free software; you can redistribute it and/or modify it
  8. under the terms of the GNU General Public License as published by the
  9. Free Software Foundation; either version 2, or (at your option) any
  10. later version.
  11.  
  12. Octave is distributed in the hope that it will be useful, but WITHOUT
  13. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with Octave; see the file COPYING.  If not, write to the Free
  19. Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  20.  
  21. */
  22.  
  23. /* Modified by Klaus Gebhardt, 1996 */
  24.  
  25. #if defined (__GNUG__)
  26. #pragma implementation
  27. #endif
  28.  
  29. #ifdef HAVE_CONFIG_H
  30. #include <config.h>
  31. #endif
  32.  
  33. #include <cstring>
  34.  
  35. #include <string>
  36.  
  37. #include <fstream.h>
  38. #include <iostream.h>
  39. #include <strstream.h>
  40.  
  41. #ifdef HAVE_UNISTD_H
  42. #ifdef HAVE_SYS_TYPES_H
  43. #include <sys/types.h>
  44. #endif
  45. #include <unistd.h>
  46. #endif
  47.  
  48. #include "SLStack.h"
  49. #include "procstream.h"
  50.  
  51. #include "file-ops.h"
  52. #include "str-vec.h"
  53.  
  54. #include "defun.h"
  55. #include "error.h"
  56. #include "gripes.h"
  57. #include "help.h"
  58. #include "load-save.h"
  59. #include "mappers.h"
  60. #include "oct-obj.h"
  61. #include "pt-cmd.h"
  62. #include "pt-exp.h"
  63. #include "pt-plot.h"
  64. #include "pt-walk.h"
  65. #include "sighandlers.h"
  66. #include "sysdep.h"
  67. #include "utils.h"
  68. #include "variables.h"
  69.  
  70. // If TRUE, a replot command is issued automatically each time a plot
  71. // changes in some way.
  72. static bool Vautomatic_replot;
  73.  
  74. // The name of the shell command to execute to start gnuplot.
  75. static string Vgnuplot_binary;
  76.  
  77. // TRUE if gnuplot appears to support multiple plot windows with X11.
  78. static bool Vgnuplot_has_frames;
  79.  
  80. // TRUE if gnuplot appears to support multiplot.
  81. static bool Vgnuplot_has_multiplot;
  82.  
  83. // The number of lines we've plotted so far.
  84. static int plot_line_count = 0;
  85.  
  86. // Is this a parametric plot?  Makes a difference for 3D plotting.
  87. static bool parametric_plot = false;
  88.  
  89. // The gnuplot terminal type.
  90. static char *gnuplot_terminal_type = 0;
  91.  
  92. // Should the graph window be cleared before plotting the next line?
  93. static bool clear_before_plotting = true;
  94.  
  95. // List of files to delete when we exit or crash.
  96. //
  97. // XXX FIXME XXX -- this should really be static, but that causes
  98. // problems on some systems.
  99. SLStack <string> tmp_files;
  100.  
  101. // Pipe to gnuplot.
  102. static oprocstream *plot_stream = 0;
  103.  
  104. // ID of the plotter process.
  105. static pid_t plot_stream_pid = 0;
  106.  
  107. // Use shortest possible abbreviations to minimize trouble caused by
  108. // gnuplot's fixed-length command line buffer.
  109.  
  110. #ifndef GPLOT_CMD_PLOT  
  111. #define GPLOT_CMD_PLOT   "pl"
  112. #endif
  113.  
  114. #ifndef GPLOT_CMD_REPLOT 
  115. #define GPLOT_CMD_REPLOT "rep"
  116. #endif
  117.  
  118. #ifndef GPLOT_CMD_SPLOT 
  119. #define GPLOT_CMD_SPLOT  "sp"
  120. #endif
  121.  
  122. #ifndef GPLOT_CMD_USING
  123. #define GPLOT_CMD_USING  "u"
  124. #endif
  125.  
  126. #ifndef GPLOT_CMD_WITH 
  127. #define GPLOT_CMD_WITH   "w"
  128. #endif
  129.  
  130. #ifndef GPLOT_CMD_TITLE
  131. #define GPLOT_CMD_TITLE  "t"
  132. #endif
  133.  
  134. #ifndef GPLOT_CMD_END
  135. #define GPLOT_CMD_END "\n"
  136. #endif
  137.  
  138. static void
  139. plot_stream_death_handler (pid_t pid, int)
  140. {
  141.   close_plot_stream ();
  142.  
  143.   warning ("connection to external plotter (pid = %d) lost --", pid);
  144.   warning ("please try your plot command(s) again");
  145. }
  146.  
  147. static void
  148. open_plot_stream (void)
  149. {
  150.   static bool initialized = false;
  151.  
  152.   if (plot_stream && ! *plot_stream)
  153.     {
  154.       delete plot_stream;
  155.       plot_stream = 0;
  156.     }
  157.  
  158.   if (! plot_stream)
  159.     {
  160.       initialized = false;
  161.  
  162.       plot_line_count = 0;
  163.  
  164.       string plot_prog = Vgnuplot_binary;
  165.  
  166.       if (plot_prog.empty ())
  167.     plot_prog = "gnuplot";
  168.  
  169.       // XXX FIXME XXX -- I'm not sure this is the right thing to do,
  170.       // but without it, C-c at the octave prompt will kill gnuplot...
  171.  
  172. #if defined (HAVE_POSIX_SIGNALS)
  173.       sigset_t set, oset;
  174.       sigemptyset (&set);
  175.       sigaddset (&set, SIGINT);
  176.       sigprocmask (SIG_BLOCK, &set, &oset);
  177. #endif
  178.  
  179. #if defined (__EMX__) && defined (OS2)
  180.       plot_stream = new oprocstream (plot_prog.c_str (), ios::out);
  181. #else
  182. #if !defined (HAVE_POSIX_SIGNALS)
  183.       volatile octave_interrupt_handler old_interrupt_handler
  184.     = octave_ignore_interrupts ();
  185. #endif
  186.       plot_stream = new oprocstream (plot_prog.c_str ());
  187. #endif
  188.       if (plot_stream)
  189.     {
  190.       if (! *plot_stream)
  191.         {
  192.           delete plot_stream;
  193.           plot_stream = 0;
  194.  
  195.           error ("plot: unable to open pipe to `%s'", plot_prog.c_str ());
  196.         }
  197.       else
  198.         {
  199.           plot_stream_pid = plot_stream->pid ();
  200.               octave_child_list::insert (plot_stream_pid,
  201.                      plot_stream_death_handler);
  202.         }
  203.     }
  204.       else
  205.     error ("plot: unable to open pipe to `%s'", plot_prog.c_str ());
  206.  
  207. #if defined (HAVE_POSIX_SIGNALS)
  208.       sigprocmask (SIG_SETMASK, &oset, 0);
  209. #else
  210. #if ! defined (__EMX__) || ! defined (OS2)
  211.       octave_set_interrupt_handler (old_interrupt_handler);
  212. #endif
  213. #endif
  214.     }
  215.  
  216.   if (! error_state && plot_stream && *plot_stream && ! initialized)
  217.     {
  218.       initialized = true;
  219.       *plot_stream << "set data style lines\n";
  220.  
  221.       if (gnuplot_terminal_type)
  222.     *plot_stream << "set term " << gnuplot_terminal_type << GPLOT_CMD_END;
  223.     }
  224. }
  225.  
  226. static int
  227. send_to_plot_stream (const char *cmd)
  228. {
  229.   if (! (plot_stream && *plot_stream))
  230.     {
  231.       open_plot_stream ();
  232.  
  233.       if (error_state)
  234.     return -1;
  235.     }
  236.  
  237.   int replot_len = strlen (GPLOT_CMD_REPLOT);
  238.   int splot_len = strlen (GPLOT_CMD_SPLOT);
  239.   int plot_len = strlen (GPLOT_CMD_PLOT);
  240.  
  241.   bool is_replot = (strncmp (cmd, GPLOT_CMD_REPLOT, replot_len) == 0);
  242.   bool is_splot = (strncmp (cmd, GPLOT_CMD_SPLOT, splot_len) == 0);
  243.   bool is_plot = (strncmp (cmd, GPLOT_CMD_PLOT, plot_len) == 0);
  244.  
  245.   if (plot_line_count == 0 && is_replot)
  246.     error ("replot: no previous plot");
  247.   else
  248.     {
  249.       *plot_stream << cmd;
  250.  
  251.       if (! (is_replot || is_splot || is_plot)
  252.       && plot_line_count > 0
  253.       && Vautomatic_replot)
  254.     *plot_stream << GPLOT_CMD_REPLOT << GPLOT_CMD_END;
  255.  
  256.       plot_stream->flush ();
  257.     }
  258.  
  259.   return 0;
  260. }
  261.  
  262. // Plotting, eh?
  263.  
  264. tree_plot_command::~tree_plot_command (void)
  265. {
  266.   delete range;
  267.   delete plot_list;
  268. }
  269.  
  270. void
  271. tree_plot_command::eval (void)
  272. {
  273.   if (error_state)
  274.     return;
  275.  
  276.   open_plot_stream ();
  277.  
  278.   ostrstream plot_buf;
  279.  
  280.   switch (ndim)
  281.     {
  282.     case 1:
  283.       if (plot_line_count == 0)
  284.     {
  285.       if (plot_list)
  286.         plot_buf << GPLOT_CMD_PLOT;
  287.       else
  288.         {
  289.           ::error ("replot: must have something to plot");
  290.           return;
  291.         }
  292.     }
  293.       else
  294.     plot_buf << GPLOT_CMD_REPLOT;
  295.       break;
  296.  
  297.     case 2:
  298.       if (clear_before_plotting || plot_line_count == 0)
  299.     {
  300.       plot_line_count = 0;
  301.       plot_buf << GPLOT_CMD_PLOT;
  302.     }
  303.       else
  304.     plot_buf << GPLOT_CMD_REPLOT;
  305.       break;
  306.  
  307.     case 3:
  308.       if (clear_before_plotting || plot_line_count == 0)
  309.     {
  310.       plot_line_count = 0;
  311.       plot_buf << GPLOT_CMD_SPLOT;
  312.     }
  313.       else
  314.     plot_buf << GPLOT_CMD_REPLOT;
  315.       break;
  316.  
  317.     default:
  318.       gripe_2_or_3_dim_plot ();
  319.       return;
  320.     }
  321.  
  322.   if (range)
  323.     {
  324.       if (plot_line_count == 0)
  325.     range->print (ndim, plot_buf);
  326.       else
  327.     warning ("can't specify new plot ranges with `replot' or while\
  328.  hold is on");
  329.     }
  330.  
  331.   if (error_state)
  332.     return;
  333.  
  334.   if (plot_list)
  335.     {
  336.       int status = plot_list->print (ndim, plot_buf);
  337.  
  338.       if (error_state || status < 0)
  339.     return;
  340.     }
  341.  
  342.   plot_buf << GPLOT_CMD_END << ends;
  343.  
  344.   // Just testing...
  345.   //  char *message = plot_buf.str ();
  346.   //  cout << "[*]" << message << "[*]\n";
  347.  
  348.   if (parametric_plot && ndim == 2)
  349.     {
  350.       warning ("can't make 2D parametric plot -- setting noparametric...");
  351.       send_to_plot_stream ("set noparametric\n");
  352.       char *message = plot_buf.str ();
  353.       send_to_plot_stream (message);
  354.       delete [] message;
  355.       send_to_plot_stream ("set parametric\n");
  356.     }
  357.   else
  358.     {
  359.       char *message = plot_buf.str ();
  360.       send_to_plot_stream (message);
  361.       delete [] message;
  362.     }
  363. }
  364.  
  365. void
  366. tree_plot_command::accept (tree_walker& tw)
  367. {
  368.   tw.visit_plot_command (*this);
  369. }
  370.  
  371. plot_limits::~plot_limits (void)
  372. {
  373.   delete x_range;
  374.   delete y_range;
  375.   delete z_range;
  376. }
  377.  
  378. void
  379. plot_limits::print (int ndim, ostrstream& plot_buf)
  380. {
  381.   if (ndim  == 2 || ndim == 3)
  382.     {
  383.       if (x_range)
  384.     x_range->print (plot_buf);
  385.       else
  386.     return;
  387.  
  388.       if (y_range)
  389.     y_range->print (plot_buf);
  390.       else
  391.     return;
  392.     }
  393.  
  394.   if (ndim == 3 && z_range)
  395.     z_range->print (plot_buf);
  396. }
  397.  
  398. void
  399. plot_limits::accept (tree_walker& tw)
  400. {
  401.   tw.visit_plot_limits (*this);
  402. }
  403.  
  404. plot_range::~plot_range (void)
  405. {
  406.   delete lower;
  407.   delete upper;
  408. }
  409.  
  410. void
  411. plot_range::print (ostrstream& plot_buf)
  412. {
  413.   plot_buf << " [";
  414.  
  415.   if (lower)
  416.     {
  417.       octave_value lower_val = lower->eval (false);
  418.       if (error_state)
  419.     {
  420.       ::error ("evaluating lower bound of plot range");
  421.       return;
  422.     }
  423.       else
  424.     {
  425.       double lo = lower_val.double_value ();
  426.       plot_buf << lo;
  427.     }
  428.     }
  429.  
  430.   plot_buf << ":";
  431.  
  432.   if (upper)
  433.     {
  434.       octave_value upper_val = upper->eval (false);
  435.       if (error_state)
  436.     {
  437.       ::error ("evaluating upper bound of plot range");
  438.       return;
  439.     }
  440.       else
  441.     {
  442.       double hi = upper_val.double_value ();
  443.       plot_buf << hi;
  444.     }
  445.     }
  446.  
  447.   plot_buf << "]";
  448. }
  449.  
  450. void
  451. plot_range::accept (tree_walker& tw)
  452. {
  453.   tw.visit_plot_range (*this);
  454. }
  455.  
  456. subplot_using::~subplot_using (void)
  457. {
  458.   delete scanf_fmt;
  459. }
  460.  
  461. int
  462. subplot_using::eval (int ndim, int n_max)
  463. {
  464.   if ((ndim == 2 && qual_count > 4)
  465.       || (ndim == 3 && qual_count > 3))
  466.     return -1;
  467.  
  468.   if (qual_count > 0)
  469.     val.resize (qual_count);
  470.  
  471.   for (int i = 0; i < qual_count; i++)
  472.     {
  473.       if (x[i])
  474.     {
  475.       octave_value tmp = x[i]->eval (false);
  476.       if (error_state)
  477.         {
  478.           ::error ("evaluating plot using command");
  479.           return -1;
  480.         }
  481.  
  482.       double val_tmp;
  483.       if (tmp.is_defined ())
  484.         {
  485.           val_tmp = tmp.double_value ();
  486.  
  487.           if (error_state)
  488.         return -1;
  489.  
  490.           if (xisnan (val_tmp))
  491.         {
  492.           ::error ("NaN is invalid as a column specifier");
  493.           return -1;
  494.         }
  495.  
  496.           int n = NINT (val_tmp);
  497.  
  498.           if (n < 1 || n_max > 0 && n > n_max)
  499.         {
  500.           ::error ("using: column %d out of range", n); 
  501.           return -1;
  502.         }
  503.           else
  504.         val (i) = n;
  505.         }
  506.       else
  507.         return -1;
  508.     }
  509.       else
  510.     return -1;
  511.     }
  512.  
  513.   if (scanf_fmt)
  514.     warning ("ignoring scanf format in plot command");
  515.  
  516.   return 0;
  517. }
  518.  
  519. ColumnVector
  520. subplot_using::values (int ndim, int n_max)
  521. {
  522.   int status = eval (ndim, n_max);
  523.  
  524.   if (status < 0)
  525.     return -1;
  526.  
  527.   return val;
  528. }
  529.  
  530. int
  531. subplot_using::print (int ndim, int n_max, ostrstream& plot_buf)
  532. {
  533.   int status = eval (ndim, n_max);
  534.  
  535.   if (status < 0)
  536.     return -1;
  537.  
  538.   for (int i = 0; i < qual_count; i++)
  539.     {
  540.       if (i == 0)
  541.     plot_buf << " " << GPLOT_CMD_USING << " ";
  542.       else
  543.     plot_buf << ":";
  544.  
  545.       plot_buf << val (i);
  546.     }
  547.  
  548.   return 0;
  549. }
  550.  
  551. void
  552. subplot_using::accept (tree_walker& tw)
  553. {
  554.   tw.visit_subplot_using (*this);
  555. }
  556.  
  557. subplot_style::~subplot_style (void)
  558. {
  559.   delete sp_linetype;
  560.   delete sp_pointtype;
  561. }
  562.  
  563. int
  564. subplot_style::print (ostrstream& plot_buf)
  565. {
  566.   if (! sp_style.empty ())
  567.     {
  568.       plot_buf << " " << GPLOT_CMD_WITH << " " << sp_style;
  569.  
  570.       if (sp_linetype)
  571.     {
  572.       octave_value tmp = sp_linetype->eval (false);
  573.       if (! error_state && tmp.is_defined ())
  574.         {
  575.           double val = tmp.double_value ();
  576.           if (xisnan (val))
  577.         {
  578.           ::error ("NaN is invalid a plotting line style");
  579.           return -1;
  580.         }
  581.           else
  582.         plot_buf << " " << NINT (val);
  583.         }
  584.       else
  585.         {
  586.           ::error ("evaluating plot style command");
  587.           return -1;
  588.         }
  589.     }
  590.  
  591.       if (sp_pointtype)
  592.     {
  593.       octave_value tmp = sp_pointtype->eval (false);
  594.       if (! error_state && tmp.is_defined ())
  595.         {
  596.           double val = tmp.double_value ();
  597.           if (xisnan (val))
  598.         {
  599.           ::error ("NaN is invalid a plotting point style");
  600.           return -1;
  601.         }
  602.           else
  603.         plot_buf << " " << NINT (val);
  604.         }
  605.       else
  606.         {
  607.           ::error ("evaluating plot style command");
  608.           return -1;
  609.         }
  610.     }
  611.     }
  612.   else
  613.     return -1;
  614.  
  615.   return 0;
  616. }
  617.  
  618. bool
  619. subplot_style::columns_ok (int nc)
  620. {
  621.   bool retval = true;
  622.  
  623.   if ((almost_match ("boxes", sp_style, 5, 0) && nc != 3)
  624.       || (almost_match ("boxerrorbars", sp_style, 5, 0)
  625.       && (! (nc == 3 || nc == 4 || nc == 5)))
  626.       || ((almost_match ("boxxyerrorbars", sp_style, 4, 0)
  627.        || almost_match ("xyerrorbars", sp_style, 2, 0))
  628.       && (! (nc == 4 || nc == 6 || nc == 7)))
  629.       || ((almost_match ("candlesticks", sp_style, 1, 0)
  630.        || almost_match ("financebars", sp_style, 2, 0))
  631.       && nc != 5)
  632.       || ((almost_match ("errorbars", sp_style, 1, 0)
  633.        || almost_match ("xerrorbars", sp_style, 1, 0)
  634.        || almost_match ("yerrorbars", sp_style, 1, 0))
  635.       && (! (nc == 3 || nc == 4))))
  636.     {
  637.       error
  638.     ("invalid number of data columns = %d specified for plot style `%s'",
  639.      nc, sp_style.c_str ());
  640.  
  641.       retval = false;
  642.     }
  643.  
  644.   return retval;
  645. }
  646.  
  647. void
  648. subplot_style::accept (tree_walker& tw)
  649. {
  650.   tw.visit_subplot_style (*this);
  651. }
  652.  
  653. subplot::~subplot (void)
  654. {
  655.   delete sp_plot_data;
  656.   delete sp_using_clause;
  657.   delete sp_title_clause;
  658.   delete sp_style_clause;
  659. }
  660.  
  661. octave_value
  662. subplot::extract_plot_data (int ndim, octave_value& data)
  663. {
  664.   octave_value retval;
  665.  
  666.   if (sp_using_clause)
  667.     {
  668.       ColumnVector val = sp_using_clause->values (ndim);
  669.  
  670.       octave_value_list args;
  671.       args(1) = val;
  672.       args(0) = octave_value::magic_colon_t;
  673.  
  674.       retval = data.index (args);
  675.  
  676.       if (error_state)
  677.     return octave_value ();
  678.     }
  679.   else
  680.     {
  681.       retval = data;
  682.     }
  683.  
  684.   int nc = retval.columns ();
  685.  
  686.   if (ndim == 2 && sp_style_clause && ! sp_style_clause->columns_ok (nc))
  687.     return octave_value ();
  688.  
  689.   return retval;
  690. }
  691.  
  692. int
  693. subplot::handle_plot_data (int ndim, ostrstream& plot_buf)
  694. {
  695.   if (sp_plot_data)
  696.     {
  697.       octave_value data = sp_plot_data->eval (false);
  698.  
  699.       if (! error_state && data.is_defined ())
  700.     {
  701.       string file;
  702.  
  703.       if (data.is_string ())
  704.         {
  705.           // Should really try to look at data file to determine
  706.           // n_max.  Can't do much about other arbitrary gnuplot
  707.           // commands though...
  708.  
  709.           int n_max = 0;
  710.  
  711.           file = oct_tilde_expand (data.string_value ());
  712.  
  713.           ifstream ftmp (file.c_str ());
  714.  
  715.           if (ftmp)
  716.         {
  717.           plot_buf << " \"" << file << '"';
  718.         }
  719.           else
  720.         {
  721.           file = "";
  722.  
  723.           // Opening as a file failed.  Let's try passing it
  724.           // along as a plot command.
  725.  
  726.           plot_buf << " " << data.string_value ();
  727.         }
  728.  
  729.           if (sp_using_clause)
  730.         {
  731.           int status = sp_using_clause->print (ndim, n_max, plot_buf);
  732.  
  733.           if (status < 0)
  734.             return -1;
  735.         }
  736.         }
  737.       else
  738.         {
  739.           // Eliminate the need for printing a using clause to
  740.           // plot_buf.
  741.  
  742.           octave_value tmp_data = extract_plot_data (ndim, data);
  743.  
  744.           if (tmp_data.is_defined ())
  745.         {
  746.           switch (ndim)
  747.             {
  748.             case 2:
  749.               file = save_in_tmp_file (tmp_data, ndim);
  750.               break;
  751.  
  752.             case 3:
  753.               file = save_in_tmp_file (tmp_data, ndim,
  754.                            parametric_plot);
  755.               break;
  756.  
  757.             default:
  758.               gripe_2_or_3_dim_plot ();
  759.               break;
  760.             }
  761.  
  762.           if (file.length () > 0)
  763.             {
  764.               mark_for_deletion (file);
  765.               plot_buf << " \"" << file << '"';
  766.             }
  767.         }
  768.         }
  769.     }
  770.       else
  771.     return -1;
  772.     }
  773.   else
  774.     return -1;
  775.  
  776.   return 0;
  777. }
  778.  
  779. int
  780. subplot::print (int ndim, ostrstream& plot_buf)
  781. {
  782.   int status = handle_plot_data (ndim, plot_buf);
  783.  
  784.   if (status < 0)
  785.     return -1;
  786.  
  787.   if (sp_title_clause)
  788.     {
  789.       octave_value tmp = sp_title_clause->eval (false);
  790.       if (! error_state && tmp.is_string ())
  791.     plot_buf << " " << GPLOT_CMD_TITLE << " "
  792.       << '"' << tmp.string_value () << '"';
  793.       else
  794.     {
  795.       warning ("line title must be a string");
  796.       plot_buf << " " << GPLOT_CMD_TITLE << " "
  797.         << '"' << "line " << plot_line_count << '"';
  798.     }
  799.     }
  800.   else
  801.     plot_buf << " " << GPLOT_CMD_TITLE << " "
  802.       << '"' << "line " << plot_line_count << '"';
  803.  
  804.   if (sp_style_clause)
  805.     {
  806.       int status = sp_style_clause->print (plot_buf);
  807.       if (status < 0)
  808.     return -1;
  809.     }
  810.  
  811.   return 0;
  812. }
  813.  
  814. void
  815. subplot::accept (tree_walker& tw)
  816. {
  817.   tw.visit_subplot (*this);
  818. }
  819.  
  820. subplot_list::~subplot_list (void)
  821. {
  822.   while (! empty ())
  823.     {
  824.       subplot *t = remove_front ();
  825.       delete t;
  826.     }
  827. }
  828.  
  829. int
  830. subplot_list::print (int ndim, ostrstream& plot_buf)
  831. {
  832.   int status = 0;
  833.  
  834.   for (Pix p = first (); p != 0; next (p))
  835.     {
  836.       subplot *elt = this->operator () (p);
  837.  
  838.       plot_line_count++;
  839.  
  840.       if (p != first ())
  841.     plot_buf << ",\\\n  ";
  842.  
  843.       status = elt->print (ndim, plot_buf);
  844.  
  845.       if (status < 0)
  846.     break;
  847.     }
  848.  
  849.   return status;
  850. }
  851.  
  852. void
  853. subplot_list::accept (tree_walker& tw)
  854. {
  855.   tw.visit_subplot_list (*this);
  856. }
  857.  
  858. string
  859. save_in_tmp_file (octave_value& t, int ndim, bool parametric)
  860. {
  861.   string name = oct_tempnam ();
  862.  
  863.   if (! name.empty ())
  864.     {
  865.       ofstream file (name.c_str ());
  866.  
  867.       if (file)
  868.     {
  869.       switch (ndim)
  870.         {
  871.         case 2:
  872.           save_ascii_data (file, t, name, 1);
  873.           break;
  874.  
  875.         case 3:
  876.           save_three_d (file, t, parametric);
  877.           break;
  878.  
  879.         default:
  880.           gripe_2_or_3_dim_plot ();
  881.           break;
  882.         }
  883.     }
  884.       else
  885.     {
  886.       error ("couldn't open temporary output file `%s'", name.c_str ());
  887.       name.resize (0);
  888.     }
  889.     }
  890.  
  891.   return name;
  892. }
  893.  
  894. void
  895. mark_for_deletion (const string& file)
  896. {
  897.   tmp_files.push (file);
  898. }
  899.  
  900. void
  901. cleanup_tmp_files (void)
  902. {
  903.   while (! tmp_files.empty ())
  904.     {
  905.       string filename = tmp_files.pop ();
  906.       unlink (filename.c_str ());
  907.     }
  908. }
  909.  
  910. void
  911. close_plot_stream (void)
  912. {
  913.   octave_child_list::remove (plot_stream_pid);
  914.  
  915.   if (plot_stream)
  916.     {
  917.       delete plot_stream;
  918.       plot_stream = 0;
  919.     }
  920.  
  921.   plot_line_count = 0;
  922. }
  923.  
  924. void
  925. do_external_plotter_cd (const string& newdir)
  926. {
  927.   if (plot_stream && *plot_stream)
  928.     {
  929.       ostrstream plot_buf;
  930.       plot_buf << "cd \"" << newdir << "\"" GPLOT_CMD_END << ends;
  931.       char *message = plot_buf.str ();
  932.       send_to_plot_stream (message);
  933.       delete [] message;
  934.     }
  935. }
  936.  
  937. DEFUN (clearplot, , ,
  938.   "clearplot (): clear the plot window")
  939. {
  940.   octave_value_list retval;
  941.   send_to_plot_stream ("clear\n");
  942.  
  943.   // XXX FIXME XXX -- instead of just clearing these things, it would
  944.   // be nice if we could reset things to a user-specified default
  945.   // state.
  946.  
  947.   send_to_plot_stream ("set title\n");
  948.   send_to_plot_stream ("set xlabel\n");
  949.   send_to_plot_stream ("set ylabel\n");
  950.   send_to_plot_stream ("set nogrid\n");
  951.   send_to_plot_stream ("set nolabel\n");
  952.  
  953.   // This makes a simple `replot' not work after a `clearplot' command
  954.   // has been issued.
  955.  
  956.   plot_line_count = 0;
  957.  
  958.   return retval;
  959. }
  960.  
  961. DEFALIAS (clg, clearplot);
  962.  
  963. DEFUN (closeplot, , ,
  964.   "closeplot (): close the stream to plotter")
  965. {
  966.   octave_value_list retval;
  967.   close_plot_stream ();
  968.   return retval;
  969. }
  970.  
  971. DEFUN_TEXT (hold, args, ,
  972.   "hold [on|off]\n\
  973. \n\
  974. determine whether the plot window is cleared before the next line is\n\
  975. drawn.  With no argument, toggle the current state.") 
  976. {
  977.   octave_value_list retval;
  978.  
  979.   int argc = args.length () + 1;
  980.  
  981.   string_vector argv = args.make_argv ("hold");
  982.  
  983.   if (error_state)
  984.     return retval;
  985.  
  986.   switch (argc)
  987.     {
  988.     case 1:
  989.       clear_before_plotting = ! clear_before_plotting;
  990.       break;
  991.  
  992.     case 2:
  993.       if (argv[1] == "on")
  994.     clear_before_plotting = false;
  995.       else if (argv[1] == "off")
  996.     clear_before_plotting = true;
  997.       else
  998.     print_usage ("hold");
  999.       break;
  1000.  
  1001.     default:
  1002.       print_usage ("hold");
  1003.       break;
  1004.     }
  1005.  
  1006.   return retval;
  1007. }
  1008.  
  1009. DEFUN (ishold, , ,
  1010.   "ishold\n\
  1011. \n\
  1012. Return 1 if hold is on, otherwise return 0.")
  1013. {
  1014.   return (double) (! clear_before_plotting);
  1015. }
  1016.  
  1017. DEFUN (purge_tmp_files, , ,
  1018.   "delete temporary data files used for plotting")
  1019. {
  1020.   octave_value_list retval;
  1021.   cleanup_tmp_files ();
  1022.   return retval;
  1023. }
  1024.  
  1025. DEFUN_TEXT (gset, args, ,
  1026.   "gset [options]\n\
  1027. \n\
  1028. set plotting options for gnuplot")
  1029. {
  1030.   octave_value_list retval;
  1031.  
  1032.   int argc = args.length () + 1;
  1033.  
  1034.   string_vector argv = args.make_argv ("set");
  1035.  
  1036.   if (error_state)
  1037.     return retval;
  1038.  
  1039.   ostrstream plot_buf;
  1040.  
  1041.   if (argc > 1)
  1042.     {
  1043.       if (almost_match ("parametric", argv[1], 3))
  1044.     parametric_plot = true;
  1045.       else if (almost_match ("noparametric", argv[1], 5))
  1046.     parametric_plot = false;
  1047.       else if (almost_match ("term", argv[1], 1))
  1048.     {
  1049.       delete [] gnuplot_terminal_type;
  1050.       ostrstream buf;
  1051.       for (int i = 2; i < argc; i++)
  1052.         buf << argv[i] << " ";
  1053.       buf << GPLOT_CMD_END << ends;
  1054.       gnuplot_terminal_type = buf.str ();
  1055.     }
  1056.     }
  1057.  
  1058.   for (int i = 0; i < argc; i++)
  1059.     plot_buf << argv[i] << " ";
  1060.  
  1061.   plot_buf << GPLOT_CMD_END << ends;
  1062.  
  1063.   char *plot_command = plot_buf.str ();
  1064.   send_to_plot_stream (plot_command);
  1065.  
  1066.   delete [] plot_command;
  1067.  
  1068.   return retval;
  1069. }
  1070.  
  1071. DEFUN_TEXT (set, args, nargout,
  1072.   "This command is has been replaced by `gset'.")
  1073. {
  1074.   warning ("set is obsolete -- use gset instead");
  1075.   return Fgset (args, nargout);
  1076. }
  1077.  
  1078. DEFUN_TEXT (gshow, args, ,
  1079.   "gshow [options]\n\
  1080. \n\
  1081. show plotting options")
  1082. {
  1083.   octave_value_list retval;
  1084.  
  1085.   int argc = args.length () + 1;
  1086.  
  1087.   string_vector argv = args.make_argv ("show");
  1088.  
  1089.   if (error_state)
  1090.     return retval;
  1091.  
  1092.   ostrstream plot_buf;
  1093.  
  1094.   for (int i = 0; i < argc; i++)
  1095.     plot_buf << argv[i] << " ";
  1096.  
  1097.   plot_buf << GPLOT_CMD_END << ends;
  1098.  
  1099.   char *plot_command = plot_buf.str ();
  1100.   send_to_plot_stream (plot_command);
  1101.   sleep (2);
  1102.  
  1103.   delete [] plot_command;
  1104.  
  1105.   return retval;
  1106. }
  1107.  
  1108. DEFUN_TEXT (show, args, nargout,
  1109.   "This command is has been replaced by `gshow'.")
  1110. {
  1111.   warning ("show is obsolete -- use gshow instead");
  1112.   return Fgshow (args, nargout);
  1113. }
  1114.  
  1115. static int
  1116. automatic_replot (void)
  1117. {
  1118.   Vautomatic_replot = check_preference ("automatic_replot");
  1119.  
  1120.   return 0;
  1121. }
  1122.  
  1123. int
  1124. gnuplot_binary (void)
  1125. {
  1126.   int status = 0;
  1127.  
  1128.   string s = builtin_string_variable ("gnuplot_binary");
  1129.  
  1130.   if (s.empty ())
  1131.     {
  1132.       gripe_invalid_value_specified ("gnuplot_binary");
  1133.       status = -1;
  1134.     }
  1135.   else
  1136.     Vgnuplot_binary = s;
  1137.  
  1138.   return status;
  1139. }
  1140.  
  1141. static int
  1142. gnuplot_has_frames (void)
  1143. {
  1144.   Vgnuplot_has_frames = check_preference ("gnuplot_has_frames");
  1145.  
  1146.   return 0;
  1147. }
  1148.  
  1149. static int
  1150. gnuplot_has_multiplot (void)
  1151. {
  1152.   Vgnuplot_has_multiplot = check_preference ("gnuplot_has_multiplot");
  1153.  
  1154.   return 0;
  1155. }
  1156.  
  1157. void
  1158. symbols_of_pt_plot (void)
  1159. {
  1160.   DEFVAR (automatic_replot, 0.0, 0, automatic_replot,
  1161.     "if true, auto-insert a replot command when a plot changes");
  1162.  
  1163.   DEFVAR (gnuplot_binary, "gnuplot", 0, gnuplot_binary,
  1164.     "path to gnuplot binary");
  1165.  
  1166. #ifdef GNUPLOT_HAS_FRAMES
  1167.   double with_frames = 1.0;
  1168. #else
  1169.   double with_frames = 0.0;
  1170. #endif
  1171.  
  1172.   DEFVAR (gnuplot_has_frames, with_frames, 0, gnuplot_has_frames,
  1173.     "true if gnuplot supports multiple plot windows on X11, false otherwise");
  1174.  
  1175. #ifdef GNUPLOT_HAS_MULTIPLOT
  1176.   double with_multiplot = 1.0;
  1177. #else
  1178.   double with_multiplot = 0.0;
  1179. #endif
  1180.  
  1181.   DEFVAR (gnuplot_has_multiplot, with_multiplot, 0, gnuplot_has_multiplot,
  1182.     "true if gnuplot supports multiplot, false otherwise");
  1183. }
  1184.  
  1185. /*
  1186. ;;; Local Variables: ***
  1187. ;;; mode: C++ ***
  1188. ;;; End: ***
  1189. */
  1190.